using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Reflection;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace Easy.Chat.Features.WebAppFeature
{
    /// <summary>
    /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>

    [Guid("1b2fdb62-2969-4d8c-b768-a39eac772d03")]
    public class WebAppFeatureEventReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            try
            {
                SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
                RegisterWebConfig(webApp);
            }
            catch (Exception ex)
            {
                LogError(ex.Message + "\n" + ex.StackTrace);
                throw ex;
            }
        }


        // Uncomment the method below to handle the event raised before a feature is deactivated.

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            try
            {
                SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
                UnregisterWebConfig(webApp);
            }
            catch (Exception ex)
            {
                LogError(ex.Message + "\n" + ex.StackTrace);
                throw ex;
            }
        }


        // Uncomment the method below to handle the event raised after a feature has been installed.

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
        }


        // Uncomment the method below to handle the event raised before a feature is uninstalled.

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            
        }

        // Uncomment the method below to handle the event raised when a feature is upgrading.

        //public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        //{
        //}

        private void RegisterWebConfig(SPWebApplication webApp)
        {
            SetWebConfig(webApp, false);
        }
        private void UnregisterWebConfig(SPWebApplication webApp)
        {
            SetWebConfig(webApp, true);
        }

        private void SetWebConfig(SPWebApplication webApp1, bool remove)
        {
            SPWebService webApp = SPWebService.ContentService;
            string owner = "Easy.Chat";
            SPWebConfigModification mod1 = new SPWebConfigModification("add[@key='owin:appStartup']", "configuration/appSettings");
            Type startupType = typeof(Startup);
            mod1.Owner = owner;
            mod1.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
            mod1.Value = "<add key=\"owin:appStartup\" value=\"" + startupType.AssemblyQualifiedName + "\" />";
            mod1.Sequence = 0;

            SPWebConfigModification mod2 = new SPWebConfigModification("add[@key='owin:AutomaticAppStartup']", "configuration/appSettings");
            mod2.Owner = owner;
            mod2.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
            mod2.Value = "<add key=\"owin:AutomaticAppStartup\" value=\"true\" />";
            mod2.Sequence = 0;

            SPWebConfigModification mod3 = new SPWebConfigModification("add[@name='Owin']", "configuration/system.webServer/handlers");
            mod3.Owner = owner;
            mod3.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
            Type t = typeof(Microsoft.Owin.Host.SystemWeb.OwinHttpHandler);
            mod3.Value = "<add name=\"Owin\" verb=\"*\" path=\"/signalr\" type=\"" + t.AssemblyQualifiedName + "\"/>";
            mod3.Sequence = 0;

            SPWebConfigModification legacyCasMod = new SPWebConfigModification("legacyCasModel", "configuration/system.web/trust");
            legacyCasMod.Owner = owner;
            legacyCasMod.Sequence = 0;
            legacyCasMod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute;
            legacyCasMod.Value = "false";

            if (remove)
            {

                int modsCount1 = webApp.WebConfigModifications.Count;
                for (int i = modsCount1 - 1; i > -1; i--)
                {
                    //I will remove from the web.config just the lines related to this solution and not the ones deployed from other solutions.
                    if (webApp.WebConfigModifications[i].Owner.Equals(owner))
                    {
                        webApp.WebConfigModifications.Remove(webApp.WebConfigModifications[i]);
                    }
                }

            }
            else
            {
                webApp.WebConfigModifications.Add(mod1);
                webApp.WebConfigModifications.Add(mod2);
                webApp.WebConfigModifications.Add(mod3);
                webApp.WebConfigModifications.Add(legacyCasMod);

            }

            webApp.Update();
            //WaitForOneTimeJobToFinish(webApp.Farm);
            webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
            //webApp.ApplyWebConfigModifications();
        }

        private void WaitForOneTimeJobToFinish(SPFarm farm)
        {
            float waitTime = 0;

            do
            {
                if (!IsJobDefined(farm) && !IsJobRunning(farm))
                    break;

                const int sleepTime = 500; // milliseconds

                Thread.Sleep(sleepTime);
                waitTime += (sleepTime / 1000.0F); // seconds

            } while (waitTime < 20);
        }

        private static string jobTitle = "job-webconfig-modification";
        private static bool IsJobDefined(SPFarm farm)
        {
            SPServiceCollection services = farm.Services;

            foreach (SPService service in services)
            {
                foreach (SPJobDefinition job in service.JobDefinitions)
                {
                    if (string.Compare(job.Name, jobTitle, StringComparison.OrdinalIgnoreCase) == 0)
                        return true;
                }
            }

            return false;
        }

        private bool IsJobRunning(SPFarm farm)
        {
            SPServiceCollection services = farm.Services;

            foreach (SPService service in services)
            {
                foreach (SPRunningJob job in service.RunningJobs)
                {
                    if (string.Compare(job.JobDefinition.Name, jobTitle, StringComparison.OrdinalIgnoreCase) == 0)
                        return true;
                }
            }

            return false;
        }

        private void LogError(string msg)
        {
            string source = "Easy.Chat";
            if (!EventLog.SourceExists(source))
            {
                EventLog.CreateEventSource("Easy.Chat", "Application");
            }
            EventLog.WriteEntry(source, msg, EventLogEntryType.Error);
        }
    }
}
